﻿namespace DimensionsHelper.LanguageService.Syntax;

/// <summary>
///     成员表达式，[Object].Member
/// </summary>
public class MemberExpression : Expression
{
    private SyntaxToken _dotToken;
    private Identifier _member;


    private Expression _object;

    internal MemberExpression(SyntaxNode? parent) :
        base(SyntaxKinds.MemberExpression, parent)
    {
        _object = EmptyExpression.Default;
        _dotToken = SyntaxToken.Default;
        _member = Identifier.Default;
    }


    /// <summary>
    ///     对象表达式，当表达式因为在 With 语句块中忽略对象表达式时，可以设置此属性为
    ///     <see cref="EmptyExpression" />类型值
    /// </summary>
    public Expression Object => _object;


    /// <summary>
    ///     '.' Token符号
    /// </summary>
    public SyntaxToken DotToken => _dotToken;


    /// <summary>
    ///     成员表达式，必须是标识符
    /// </summary>
    public Identifier Member => _member;


    /// <summary>
    ///     如果表达式忽略了对象表达式，返回<see langword="true" />
    /// </summary>
    public bool IsObjectMissing => _object.IsEmpty;


    public MemberExpression Update(Expression @object)
    {
        SetChildField(ref _object, IsEmptyExpression, @object);
        return this;
    }


    public MemberExpression Update(SyntaxToken dotToken)
    {
        SetChildField(ref _dotToken, SyntaxToken.IsNullOrEmpty, dotToken);
        return this;
    }


    public MemberExpression Update(Identifier member)
    {
        SetChildField(ref _member, Identifier.IsDefaultOrEmpty, member);
        return this;
    }


    public override void AcceptVisitor<T>(SyntaxNodeVisitor<T> visitor)
    {
        if (!IsObjectMissing)
        {
            Accept(visitor, Object);
        }

        if (!Identifier.IsDefaultOrEmpty(Member))
        {
            Accept(visitor, Member);
        }

        base.AcceptVisitor(visitor);
    }
}


public static partial class NodeFactory
{
    public static MemberExpression CreateMemberExpression(SyntaxNode? parent, Expression obj, SyntaxToken dotToken,
        Identifier member)
    {
        MemberExpression expr = new(parent);
        return expr.Update(obj).Update(dotToken).Update(member);
    }
}